/*
*功能：ESP8266连接阿里云服务，并简单的点个灯！
*作者：刘泽文
*时间：2020/4/10
*/
 
#include <ESP8266WiFi.h>
#include <ArduinoJson.h>
#include <aliyun_mqtt.h>
#include <U8g2lib.h>
#include <Wire.h>
#include <SHA256.h>
 
//定义OLED型号
U8G2_SSD1306_128X64_NONAME_F_HW_I2C u8g2(U8G2_R0, /* reset=*/ U8X8_PIN_NONE);
 
//定义DHT11引脚和型号，暂时没用到！
//#define DHT11_PIN 12
 
//定义LED灯
#define LED0 D4
 
//初始化次态
int redLedState0 = 0;
 
//初始化现态
int last0 = 0;
 
//上云时间现态
unsigned long lastSend = 0;
unsigned long back_time = 0;
unsigned long BACK_TIME = 1*100;
 
//你的wifi
#define WIFI_SSID "liuzewen"
#define WIFI_PASSWD "17609245102liu"
 
//阿里云三元组
#define PRODUCT_KEY "a12PsBrKNbA"
#define DEVICE_NAME "MYLED"
#define DEVICE_SECRET "5UABbDCGJcdlYZrrYuonEzYHmFI249DN"
 
//Alink JSON所需
#define ALINK_BODY_FORMAT "{\"id\":\"123\",\"version\":\"1.0\",\"method\":\"%s\",\"params\":%s}"
//属性上报Topic---发布
#define ALINK_TOPIC_PROP_POST "/sys/" PRODUCT_KEY "/" DEVICE_NAME "/thing/event/property/post"
//属性设置Topic---订阅
#define ALINK_TOPIC_PROP_SET "/sys/" PRODUCT_KEY "/" DEVICE_NAME "/thing/service/property/set"
 
#define ALINK_METHOD_PROP_POST "thing.event.property.post"
 
//创建WiFiClient实例
WiFiClient espClient;
 
//创建MqttClient实例
PubSubClient mqttClient(espClient);
 
 
//连接Wifi
void initWifi(const char *ssid, const char *password)
{
  WiFi.mode(WIFI_STA);
  WiFi.begin(ssid, password);
 
  while (WiFi.status() != WL_CONNECTED)
  {
    Serial.println("WiFi does not connect, try again ...");
    delay(1000);
  }
 
  Serial.println("Wifi is connected.");
  Serial.println("IP address: ");
  Serial.println(WiFi.localIP());
}
 
 
//连接Mqtt并订阅属性设置Topic
void mqttCheckConnect()
{
    bool connected = connectAliyunMQTT(mqttClient, PRODUCT_KEY, DEVICE_NAME, DEVICE_SECRET);
 
    if (connected)
    {
        Serial.println("MQTT connect succeed!");
 
        //订阅属性设置Topic
        mqttClient.subscribe(ALINK_TOPIC_PROP_SET); 
        Serial.println("subscribe done");
    }
}

// 上报属性Topic数据
void mqttIntervalPost() 
{
    char param[256];
    char jsonBuf[512];
   
    sprintf(param, "{\"S_D0\":%d}", !digitalRead(LED0));
    sprintf(jsonBuf, ALINK_BODY_FORMAT, ALINK_METHOD_PROP_POST, param);
    //jsonBuf = "{\"id\":\"123\",\"version\":\"1.0\",\"method\":\"thing.event.property.post\",\"params\":"\{\"S_D0\":%d}\"}"
 
    Serial.println(jsonBuf);
 
    mqttClient.publish(ALINK_TOPIC_PROP_POST, jsonBuf); 
}
 
 
//监听云端下发指令并处理 
void callback(char *topic, byte *payload, unsigned int length)
{
     
    Serial.println();
    Serial.println();
    Serial.print("Message arrived [");
    Serial.print(topic);
    Serial.print("] ");
    Serial.println();
    //云端下发属性设置topic = "[/sys/你的密钥/你的设备密码/thing/service/property/set]"
 
    payload[length] = '\0';
    Serial.println((char *)payload);
    //payload = "{"method":"thing.service.property.set","id":"282860794","params":{"S_D0":1},"version":"1.0.0"}"
 
 
  if (strstr(topic, ALINK_TOPIC_PROP_SET))
    {
        //json解析payload
        StaticJsonBuffer<400> jsonBuffer;
        JsonObject &root = jsonBuffer.parseObject(payload);
 
        //判断json解析是否成功
        if (!root.success())
        {   
            Serial.println("parseObject() failed");
        } 
        else
        {
            Serial.println("parseObject() success");
 
            //redLedState0  = json解析后的"S_D0"的值
            redLedState0 = root["params"]["S_D0"];
 
            Serial.print(redLedState0);
            Serial.println(" set  sucess");
            Serial.println();
     
            Serial.print("LED0 State: ");
            Serial.println(redLedState0);
 
            digitalWrite(LED0, !redLedState0);
 
        }
    }
}
 
void u8g2_faution()
{
    u8g2.clearBuffer();
    u8g2.setFont(u8g2_font_wqy16_t_gb2312);
    u8g2.setCursor(0, 16);
    u8g2.print("   阿里云测试   ");//一行共8个汉字
    u8g2.setCursor(10, 55);
    u8g2.print("灯1状态：");
    u8g2.setFont(u8g2_font_open_iconic_all_4x_t);
    if(!digitalRead(LED0))
      u8g2.drawGlyph(85,64,120);//开灯
    else
      u8g2.drawGlyph(85,64,121);//关灯
    u8g2.sendBuffer();
}
 
void setup() 
{
    Serial.begin(9600);
 
    u8g2.begin();
    u8g2.enableUTF8Print();
    u8g2.clearBuffer();
    u8g2.setFont(u8g2_font_wqy16_t_gb2312);
    u8g2.setCursor(40, 40);
    u8g2.print("阿里云");
    u8g2.sendBuffer();
 
    pinMode(LED0, OUTPUT); 
    digitalWrite(LED0, HIGH); /*LOW*/
 
    initWifi(WIFI_SSID, WIFI_PASSWD); 
 
    Serial.println();
    Serial.println();
 
    mqttCheckConnect(); //初始化首次链接
    mqttIntervalPost(); //上报初始化数据
 
    Serial.println();
    mqttClient.setCallback(callback); // 回调，监听云端下发指令，当ESP8266收到订阅Topic后调用callback函数
 
    back_time = millis();
}
 
 
void loop()
{
    if(millis()-back_time >= BACK_TIME){
      back_time = millis();
      u8g2_faution();
    }
    //每隔1s尝试连接一次云
    if (millis() - lastSend >= 50000)
    {
        mqttCheckConnect(); 
        lastSend = millis();
    }
 
    //判断灯现态与次态的关系，减少无意义的上报  
    if (last0 != redLedState0)
    {
        last0 = redLedState0;
        
        mqttIntervalPost(); 
        Serial.println();
    }
 
    mqttClient.loop();
}
 